package com.songyang.yougnsql.core.data.dataItem;

import com.songyang.yougnsql.core.data.DataManagerImpl;
import com.songyang.yougnsql.core.data.page.Page;

import java.util.Arrays;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * dataItem 结构如下：
 * [ValidFlag] [DataSize] [Data]
 * ValidFlag 1字节，0为合法，1为非法
 * DataSize  2字节，标识Data的长度
 */
public class DataItemImpl implements DataItem {

    protected static final int OF_VALID = 0;
    protected static final int OF_SIZE = 1;
    protected static final int OF_DATA = 3;
    protected static final byte INVALID = 1;
    protected static final byte VALID = 0;

    private final byte[] raw;
    private final byte[] oldRaw;
    private final Lock rLock;
    private final Lock wLock;
    private final DataManagerImpl dm;
    private final long uid;
    private final Page page;

    public DataItemImpl(byte[] raw, byte[] oldRaw, Page page, long uid, DataManagerImpl dm) {
        this.raw = raw;
        this.oldRaw = oldRaw;
        ReadWriteLock lock = new ReentrantReadWriteLock();
        rLock = lock.readLock();
        wLock = lock.writeLock();
        this.dm = dm;
        this.uid = uid;
        this.page = page;
    }



    /**
     * 判断该条dataItem是否合法
     *
     * @return 结果
     */
    public boolean isValid() {
        return raw[OF_VALID] == VALID;
    }

    @Override
    public byte[] data() {
//        return new SubArray(raw.raw, raw.start+OF_DATA, raw.end);
        return Arrays.copyOfRange(raw, OF_DATA, raw.length);
    }

    @Override
    public void before() {
        wLock.lock();
        page.setDirty(true);
        System.arraycopy(raw, 0, oldRaw, 0, oldRaw.length);
    }


    @Override
    public void unBefore() {
        System.arraycopy(oldRaw, 0, raw, 0, oldRaw.length);
        wLock.unlock();
    }

    @Override
    public void after(long xid) {
        dm.logDataItem(xid, this);
        wLock.unlock();
    }

    @Override
    public void release() {
       dm.releaseDataItem(this);
    }

    @Override
    public void lock() {
        wLock.lock();
    }

    @Override
    public void unlock() {
        wLock.unlock();
    }

    @Override
    public void rLock() {
        rLock.lock();
    }

    @Override
    public void rUnLock() {
        rLock.unlock();
    }

    @Override
    public Page page() {
        return page;
    }

    @Override
    public long getUid() {
        return uid;
    }

    @Override
    public byte[] getOldRaw() {
        return oldRaw;
    }

    @Override
    public byte[] getRaw() {
        return raw;
    }

}
